﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace ThreadSafeControls {
    partial class ThreadSafeListViewItem {
        public class ListViewSubItemCollection : IList<ListViewSubItem>, IList {

            private readonly ListViewItem _listViewItem;
            private readonly ThreadSafeListView _listView;

            internal ListViewSubItemCollection(ListViewItem listViewItem, ThreadSafeListView listView) {
                if (listViewItem == null)
                    throw new ArgumentNullException("listViewItem");
                else if (listView == null)
                    throw new ArgumentNullException("listView");

                _listViewItem = listViewItem;
                _listView = listView;
            }

            public IList<ListViewSubItem> Synchronize() {
                return new SynchronizedObjectCollection<ListViewSubItem, ListViewSubItemCollection>(this);
            }

            public int Count {
                get { return _listView.ReturnAsync(c => _listViewItem.SubItems.Count); }
            }

            public ListViewSubItem this[int index] {
                get { return _listView.ReturnAsync(c => _listViewItem.SubItems[index]).AsThreadSafe(_listView); }
                set { _listView.UpdateAsync(c => _listViewItem.SubItems[index] = value.SubItem); }
            }

            public ListViewSubItem this[string key] {
                get { return _listView.ReturnAsync(c => _listViewItem.SubItems[key]).AsThreadSafe(_listView); }
            }

            public ListViewSubItem Add(string text) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.Add(text)).AsThreadSafe(_listView);
            }

            public ListViewSubItem Add(ListViewItem.ListViewSubItem subItem) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.Add(subItem)).AsThreadSafe(_listView);
            }

            public void Add(ListViewSubItem subItem) {
                Add(subItem.SubItem);
            }

            public bool Contains(ListViewItem.ListViewSubItem subItem) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.Contains(subItem));
            }

            public bool Contains(ListViewSubItem subItem) {
                return Contains(subItem.SubItem);
            }

            public bool ContainsKey(string key) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.ContainsKey(key));
            }

            public void CopyTo(ListViewSubItem[] dest, int index) {
                var array = Enumerate().ToArray();
                array.CopyTo(array, index);
            }

            public void Clear() {
                _listView.UpdateAsync(c => _listViewItem.SubItems.Clear());
            }

            public int IndexOf(ListViewItem.ListViewSubItem subItem) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.IndexOf(subItem));
            }

            public int IndexOf(ListViewSubItem subItem) {
                return IndexOf(subItem.SubItem);
            }

            public int IndexOfKey(string key) {
                return _listView.ReturnAsync(c => _listViewItem.SubItems.IndexOfKey(key));
            }

            public void Insert(int index, ListViewItem.ListViewSubItem subItem) {
                _listView.UpdateAsync(c => _listViewItem.SubItems.Insert(index, subItem));
            }

            public void Insert(int index, ListViewSubItem subItem) {
                Insert(index, subItem.SubItem);
            }

            public void RemoveAt(int index) {
                _listView.UpdateAsync(c => _listViewItem.SubItems.RemoveAt(index));
            }

            public void Remove(ListViewItem.ListViewSubItem subItem) {
                _listView.UpdateAsync(c => _listViewItem.SubItems.Remove(subItem));
            }

            public bool Remove(ListViewSubItem subItem) {
                Remove(subItem.SubItem);
                return true;
            }

            public void RemoveByKey(string key) {
                _listView.UpdateAsync(c => _listViewItem.SubItems.RemoveByKey(key));
            }

            public IEnumerator<ListViewSubItem> GetEnumerator() {
                return Enumerate().GetEnumerator();
            }

            private IEnumerable<ListViewSubItem> Enumerate() {
                return _listView.ReturnAsync(c => _listViewItem.SubItems)
                    .Cast<ListViewItem.ListViewSubItem>()
                    .Select(i => i.AsThreadSafe(_listView));
            }

            #region Explicit Interface Members

            object IList.this[int index] {
                get { return this[index]; }
                set { _listView.UpdateAsync(c => ((IList)_listViewItem.SubItems)[index] = value); }
            }

            bool IList.IsFixedSize {
                get { return false; }
            }

            bool IList.IsReadOnly {
                get { return false; }
            }

            bool ICollection<ListViewSubItem>.IsReadOnly {
                get { return false; }
            }

            bool ICollection.IsSynchronized {
                get { return false; }
            }

            object ICollection.SyncRoot {
                get { return ((ICollection)_listViewItem.SubItems).SyncRoot; }
            }

            int IList.Add(object value) {
                return _listView.ReturnAsync(c => ((IList)_listViewItem.SubItems).Add(value));
            }

            bool IList.Contains(object value) {
                return _listView.ReturnAsync(c => ((IList)_listViewItem.SubItems).Contains(value));
            }

            void ICollection.CopyTo(Array dest, int index) {
                var array = Enumerate().ToArray();
                array.CopyTo(array, index);
            }

            int IList.IndexOf(object value) {
                return _listView.ReturnAsync(c => ((IList)_listViewItem.SubItems).IndexOf(value));
            }

            void IList.Insert(int index, object value) {
                _listView.UpdateAsync(c => ((IList)_listViewItem.SubItems).Insert(index, value));
            }

            void IList.Remove(object value) {
                _listView.UpdateAsync(c => ((IList)_listViewItem.SubItems).Remove(value));
            }

            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator();
            }

            #endregion
        }
    }
}
